(ns futureLife.core
  (:require [clojure.string :as string]
            [futureLife.lunar :as lunar]
            [clojure.pprint :as p])
  (:import org.joda.time.DateTime
           org.joda.time.format.DateTimeFormat))

(def jiazi-nayin-file "甲子纳音.txt")
(def shichen-ganzhi-file "时辰干支查算表.txt")
(def ganzhi-wuxing-file "天干地支-五行对照表.txt")
(def siziduan-file "邵康节-生命四字断.txt")
(def siziduan-explain-file "邵康节-生命四字断-部分解释.txt")

(defn read-file
  "读取文件，以行为单位，返回一个数组"
  [file-name]
  (-> (Thread/currentThread)
      .getContextClassLoader
      (.getResource file-name)
      slurp
      string/split-lines))

(defn init-siziduan-explain
  "读取四字断解释文件，生成map"
  [file-name]
  (reduce merge (map #(apply hash-map (string/split % #":")) (read-file file-name))))

; 四字断部分解释
(def siziduan-explain (init-siziduan-explain siziduan-explain-file))

(defn init-siziduan
  "读取邵康节－生命四字断文件，生成双层map"
  [file-name]
  (let [file-content (read-file file-name)]
    (loop [main-map {}
           items (rest file-content)
           item (first file-content)
           key nil
           values ""]
      (if item
        (if (< (count item) 8)
          ; 如果是“甲木生于正月”这样的句子（6个字），此item做为第一级key
          (recur (if (> (count values) 0)
                   (assoc main-map key values)
                   main-map)
                 (rest items)
                 (first items)
                 item
                 {})
          (recur main-map
                 (rest items)
                 (first items)
                 key
                 (merge values (apply hash-map (string/split item #" ")))))
        (assoc main-map key values)))))
; 四字断数据，以年干为第一级key，时辰为第二级key，断语做为value
(def siziduan (init-siziduan siziduan-file))

(defn init-ganzhi-wuxing
  "读取天干地支－五行对照表文件，初始化map"
  [file-name]
  (reduce merge (map #(apply hash-map (string/split % #"-")) (read-file file-name))))
; 天干地支－五行映射
(def ganzhi-wuxing (init-ganzhi-wuxing ganzhi-wuxing-file))

(defn init-jiazi-nayin
  "读取甲子纳音文件初始化map"
  [file-name]
  (reduce merge (map #(apply hash-map (string/split % #" ")) (read-file file-name))))

(def jiazi-nayin
  "甲子纳音，以年干为key"
  (let [temp (init-jiazi-nayin jiazi-nayin-file)]
    (reduce merge (map #(let [key (key %) value (val %)]
                      {(.substring key 0 2) value,(.substring key 2) value})
                    temp))))

(defn generate-hour-shichen
  "生成小时－时辰map"
  [[hour shichen & other]]
  (if (= hour "时间")
    nil
    (let [[hour1 hour2] (string/split hour #"-")
          hour3 (dec (bigint hour2))
          hour4 (bigint hour1)]
      (hash-map hour3 shichen
                hour4 shichen))))

(defn generate-hour-ganzhi
  "生成小时－干支map"
  [[hour shichen & other]]
  (if (= hour "时间")
    nil
    (let [[hour1 hour2] (string/split hour #"-")
          hour3 (dec (bigint hour2))
          hour4 (bigint hour1)]
      (hash-map hour3 other
                hour4 other))))

(defn init-shichen-ganzhi
  "读取时辰干支查算表文件，初始化map"
  [file-name]
  (let [file-content (read-file file-name)]
    (map #(string/split % #"\s+") file-content)))
; 时辰干支文件原始文件，初步解析
(def shichen-ganzhi (init-shichen-ganzhi shichen-ganzhi-file))

; 小时－时辰映射
(def hour-shichen (reduce merge (map generate-hour-shichen shichen-ganzhi)))
; 小时－时辰干支映射
(def hour-ganzhi (reduce merge (map generate-hour-ganzhi shichen-ganzhi)))
; 日干数组，配合上边的“小时－时辰干支”使用
(def ganzhi-array (subvec (first shichen-ganzhi) 2))

(defn calculate-shigan
  "根据出生时间（小时）和日干推算时辰"
  [hour rigan]
  (let [index (loop [index 0
                     array ganzhi-array]
                (if (first array)
                  (if (.contains (first array) rigan)
                    index
                    (recur (+ 1 index) (rest array)))
                  nil))]
    (if index (nth (hour-ganzhi hour) index) nil)))

(defn calculate-future
  "根据日期推算四字断、对应的解释（部分）、甲子纳音"
  [query-date]
  (let [lunar (lunar/get-lunar query-date)
        rigan (str (first (:ganzhi-day lunar)))
        shi-ganzhi (calculate-shigan (.getHourOfDay query-date) rigan)
        day-siziduan (siziduan (str rigan (ganzhi-wuxing rigan) "生于" (:month-name lunar) "月"))
        shi-siziduan (day-siziduan shi-ganzhi)
        future {:siziduan shi-siziduan
                :explain (siziduan-explain shi-siziduan)
                :jiazi-nayin (jiazi-nayin (:ganzhi-year lunar))}]
    (merge future lunar)))

(defn -main
  [query-date-str]
  (let [query-date (DateTime/parse query-date-str (DateTimeFormat/forPattern "yyyy-MM-dd HH:mm:ss"))
        future (calculate-future query-date)]
    (p/pprint future)
    future))